﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DataConverter.cs" company="Data Ductus Malmö">
//   (c) 2010 - 2012 Data Ductus Malmö AB
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace DataDuctus.Snmp.Persistor.Core.Persistor.Internal
{
  using System;
  using System.Net;

  using DataDuctus.Snmp.Persistor.Core.MetaData;

  using Lextm.SharpSnmpLib;

  /// <summary>
  /// The data converter.
  /// </summary>
  internal class DataConverter
  {
    #region Methods

    /// <summary>
    /// The convert to entity type.
    /// </summary>
    /// <param name="property">
    /// The property.
    /// </param>
    /// <param name="value">
    /// The value.
    /// </param>
    /// <returns>
    /// The System.Object.
    /// </returns>
    internal static object ConvertToEntityType(PropertyMeta property, ISnmpData value)
    {
      if (null == property.Converter)
      {
        return SnmpTypeToNetType(value);
      }

      return property.Converter.ConvertTo(value, property.Property.PropertyType);
    }

    /// <summary>
    /// The convert to snmp type.
    /// </summary>
    /// <param name="property">
    /// The property.
    /// </param>
    /// <param name="value">
    /// The value.
    /// </param>
    /// <returns>
    /// The Lextm.SharpSnmpLib.ISnmpData.
    /// </returns>
    internal static ISnmpData ConvertToSnmpType(PropertyMeta property, object value)
    {
      if (null == property.Converter)
      {
        return NetToSnmpType(value);
      }

      return (ISnmpData)property.Converter.ConvertFrom(value);
    }

    /// <summary>
    /// The net to snmp type.
    /// </summary>
    /// <param name="value">
    /// The value.
    /// </param>
    /// <returns>
    /// The Lextm.SharpSnmpLib.ISnmpData.
    /// </returns>
    private static ISnmpData NetToSnmpType(object value)
    {
      if (null == value)
      {
        return new Null();
      }

      Type type = value.GetType();

      if (type == typeof(int))
      {
        return new Integer32((int)value);
      }

      if (type == typeof(string))
      {
        return new OctetString((string)value);
      }

      if (type == typeof(uint))
      {
        return new Integer32((int)value);
      }

      if (type == typeof(TimeSpan))
      {
        return new TimeTicks((uint)(((TimeSpan)value).TotalMilliseconds / 10));
      }

      if (type == typeof(ObjectIdentifier))
      {
        return (ISnmpData)value;
      }

      if (type == typeof(ulong))
      {
        return new Counter64((ulong)value);
      }

      if (type == typeof(IPAddress))
      {
        return new IP(value.ToString());
      }

      if (type.IsEnum)
      {
        return new Integer32((int)value);
      }

      return null;
    }

    /// <summary>
    /// Converts the snmp type into net type value.
    /// </summary>
    /// <param name="value">
    /// The value.
    /// </param>
    /// <returns>
    /// The net equivalent value for <see cref="ISnmpData.TypeCode"/> in <paramref name="value"/>.
    /// </returns>
    /// <exception cref="ArgumentException">If <see cref="ISnmpData.TypeCode"/> in <paramref name="value"/> is not supported.</exception>
    private static object SnmpTypeToNetType(ISnmpData value)
    {
      switch (value.TypeCode)
      {
        case SnmpType.Counter32:
          return ((Counter32)value).ToUInt32();

        case SnmpType.Counter64:
          return ((Counter64)value).ToUInt64();

        case SnmpType.Gauge32:
          return ((Gauge32)value).ToUInt32();

        case SnmpType.Integer32:
          return ((Integer32)value).ToInt32();

        case SnmpType.IPAddress:
          return ((IP)value).ToIPAddress();

        case SnmpType.NetAddress:
          return ((IP)value).ToIPAddress();

        case SnmpType.Null:
          return null;

        case SnmpType.OctetString:
          return ((OctetString)value).ToString();

        case SnmpType.Opaque:
        case SnmpType.ObjectIdentifier:
          return value;

        case SnmpType.TimeTicks:
          return ((TimeTicks)value).ToTimeSpan();

        case SnmpType.UInt32:
          return ((Integer32)value).ToInt32();
      }

      throw new ArgumentException(string.Format("Cannot convert the ISnmpData (Type = {0}", value.TypeCode), "value");
    }

    #endregion
  }
}